﻿//using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Collections;
using UnityEngine;
using GameFramework;

namespace MYSTARFORCE
{
    public static class AIUtility
    {
        /// <summary>
        /// 阵营与关系对应的字典
        /// </summary>
        private static Dictionary<CampPair, RelationType> s_CampPairToRelation = new Dictionary<CampPair, RelationType>();

        static AIUtility(){
            s_CampPairToRelation.Add(new CampPair(CampType.Player, CampType.Player), RelationType.Firendly);
            s_CampPairToRelation.Add(new CampPair(CampType.Player, CampType.Neutral), RelationType.Neutral);
            s_CampPairToRelation.Add(new CampPair(CampType.Player, CampType.Enemy), RelationType.Hostile);

            s_CampPairToRelation.Add(new CampPair(CampType.Enemy, CampType.Enemy), RelationType.Firendly);
            s_CampPairToRelation.Add(new CampPair(CampType.Enemy, CampType.Neutral), RelationType.Neutral);
            
            s_CampPairToRelation.Add(new CampPair(CampType.Neutral, CampType.Neutral), RelationType.Neutral);
        }

        /// <summary>
        /// 获取阵营所对应的阵营关系
        /// </summary>
        /// <param name="first">第一个的阵营</param>
        /// <param name="second">第二个的阵营</param>
        /// <returns>阵营关系</returns>
        public static RelationType GetRelation(CampType first, CampType second)
        {
            // 如果第一个阵营的数字比第二个阵营大，就交换一下两者，使first始终小于等于second
            if(first > second)
            {
                CampType temp = first;
                first = second;
                second = temp;
            }

            RelationType relationType;
            // 尝试从字典中找到对应的关系，并将结果返回给relationType。
            if (s_CampPairToRelation.TryGetValue(new CampPair(first, second), out relationType))
            {
                // 如果找到了，就会返回对应的关系；如果找不到，那么这个值就会是false。
                return relationType;
            }

            Log.Warning("Unknown relation between '{0}' and '{1}'.", first.ToString(), second.ToString());
            // 否则在字典中找不到关系，就返回Unkonw
            return RelationType.Unknow;
        }

        /// <summary>
        /// 执行碰撞
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="other"></param>
        public static void PerformCollision(TargetableObject entity, Entity other)
        {
            // 步骤如下：
            // 1.检查两者是否都是存在的
            // 2.比较两者的关系，如果是友善的，就跳过
            // 3.如果不是友善的，就获取双方的攻防数据
            // 4.根据各自攻防数据计算各自的掉血情况

            // 1.检查两者是否都是存在的
            if (entity == null || other == null)
            {
                return;
            }
            // 尝试将other转换成TargetableObject类型.
            // 使用as方法进行类型转换比使用（TargetableObject）other 这种方式进行转换会更安全一些。
            // 具体方法可以查看这篇文章：https://www.cnblogs.com/xiatianoo/p/5892330.html
            TargetableObject target = other as TargetableObject;

            if(target != null)
            {
                // 如果target的确是TargetableObject类型的，就会执行下面的代码
                // 获取两者的碰撞数据
                ImpactData entityImpactData = entity.GetImpactData();
                ImpactData targetImpactData = target.GetImpactData();

                // 获取两者的阵营关系
                RelationType relationType = GetRelation(entityImpactData.Camp, targetImpactData.Camp);
                if (relationType == RelationType.Firendly)
                {
                    // 如果友好，就退出
                    return;
                }

                // 计算两者各自所受到的伤害
                int entityDamageHp = CalcDamageHp(targetImpactData.Attack, entityImpactData.Defense);
                int targetDamageHp = CalcDamageHp(entityImpactData.Attack, targetImpactData.Defense);

                int delta = Mathf.Min(entityImpactData.HP - entityDamageHp, targetImpactData.HP - targetDamageHp);

                if (delta > 0)
                {
                    entityDamageHp += delta;
                    targetDamageHp += delta;
                }
                entity.ApplyDamage(target, entityDamageHp);
                target.ApplyDamage(entity, targetDamageHp);
                return;
            }
            //TODO：target除了是TargetableObject的类型，还可以是bullet子弹类型
            Bullet bullet = other as Bullet;
            // 如果对方物体是子弹
            if(bullet != null)
            {
                ImpactData entityImpactData = entity.GetImpactData();
                ImpactData bulletImpactData = bullet.GetImpactData();
                if(GetRelation(entityImpactData.Camp,bulletImpactData.Camp) == RelationType.Firendly)
                {
                    return;
                }

                int entityDamageHp = CalcDamageHp(bulletImpactData.Attack, entityImpactData.Defense);

                entity.ApplyDamage(bullet, entityDamageHp);

                GameEntry.Entity.HideEntity(bullet);
                return;
            }

        }

        /// <summary>
        /// 计算伤害
        /// </summary>
        /// <param name="attack">攻击方的攻击力</param>
        /// <param name="defense">防御方的防御力</param>
        /// <returns></returns>
        private static int CalcDamageHp(int attack, int defense)
        {
            if(attack <= 0)
            {
                return 0;
            }

            if(defense < 0)
            {
                defense = 0;
            }
            return attack * attack / (attack + defense);
        }
        /// <summary>
        /// 阵营配对
        /// </summary>
        [StructLayout(LayoutKind.Auto)]
        private struct CampPair
        {
            // 声明两个只读字段，当这个结构体被初始化之后，就不允许它们发生变化
            private readonly CampType m_First;
            private readonly CampType m_Second;

            public CampPair(CampType first, CampType second)
            {
                m_First = first;
                m_Second = second;
            }

            public CampType First
            {
                get
                {
                    return m_First;
                }
            }

            public CampType Second
            {
                get
                {
                    return m_Second;
                }
            }

        }
    }
}